1 Example hpgltool usage with a real data set (fission)

This document aims to provide further examples in how to use the hpgltools.

Note to self, the header has rmarkdown::pdf_document instead of html_document or html_vignette because it gets some bullcrap error ‘margins too large’…

1.1 Setting up

Here are the commands I invoke to get ready to play with new data, including everything required to install hpgltools, the software it uses, and the fission data.

library(hpgltools)
tt <- sm(library(fission))
tt <- data(fission)

1.2 Annotation collection

Later on in this, I will do some ontology shenanigans. But I can grab some annotations from biomart now.

pombe_annotations <- sm(load_biomart_annotations(
  host="fungi.ensembl.org",
  trymart="fungal_mart",
  trydataset="spombe_eg_gene",
  gene_requests=c("pombase_transcript", "ensembl_gene_id", "ensembl_transcript_id",
                  "hgnc_symbol", "description", "gene_biotype"),
  species="spombe", overwrite=TRUE))
## Error in message("Unable to perform useMart, perhaps the host/mart is incorrect: ", : object 'host' not found
pombe_mart <- pombe_annotations[["mart"]]
## Error in eval(expr, envir, enclos): object 'pombe_annotations' not found
annotations <- pombe_annotations[["annotation"]]
## Error in eval(expr, envir, enclos): object 'pombe_annotations' not found
rownames(annotations) <- make.names(gsub(pattern="\\.\\d+$",
                                         replacement="",
                                         x=rownames(annotations)), unique=TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'gsub': error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'annotations' not found

1.3 Data import

All the work I do in Dr. El-Sayed’s lab makes some pretty hard assumptions about how data is stored. As a result, to use the fission data set I will do a little bit of shenanigans to match it to the expected format. Now that I have played a little with fission, I think its format is quite nice and am likely to have my experiment class instead be a SummarizedExperiment.

## Extract the meta data from the fission dataset
meta <- as.data.frame(fission@colData)
## Make conditions and batches
meta$condition <- paste(meta$strain, meta$minute, sep=".")
meta$batch <- meta$replicate
meta$sample.id <- rownames(meta)
## Grab the count data
fission_data <- fission@assays$data$counts
## This will make an experiment superclass called 'expt' and it contains
## an ExpressionSet along with any arbitrary additional information one might want to include.
## Along the way it writes a Rdata file which is by default called 'expt.Rdata'
fission_expt <- create_expt(metadata=meta,
                            count_dataframe=fission_data,
                            gene_info=annotations)
## Reading the sample metadata.
## The sample definitions comprises: 36 rows(samples) and 7 columns(metadata fields).
## Error in create_expt(metadata = meta, count_dataframe = fission_data, : object 'annotations' not found

2 Some simple differential expression analyses

Travis wisely imposes a limit on the amount of time for building vignettes. My tools by default will attempt all possible pairwise comparisons, which takes a long time. Therefore I am going to take a subset of the data and limit these comparisons to that.

fun_data <- subset_expt(fission_expt,
                        subset="condition=='wt.120'|condition=='wt.30'")
## Using a subset expression.
## There were 36, now there are 6 samples.
fun_filt <- normalize_expt(fun_data, filter="simple")
## This function will replace the expt$expressionset slot with:
## simple(data)
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: simple
## Removing 462 low-count genes (6577 remaining).
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: not transforming the data.
## Step 5: not doing batch correction.
fun_norm <- sm(normalize_expt(fun_filt, batch="limma", norm="quant",
                              transform="log2", convert="cpm"))

2.1 Try using limma first

limma_comparison <- sm(limma_pairwise(fun_data))

names(limma_comparison$all_tables)
## [1] "wt30_vs_wt120"
summary(limma_comparison$all_tables$wt30_vs_wt120)
##      logFC           AveExpr            t             P.Value      
##  Min.   :-4.278   Min.   :-4.58   Min.   :-88.48   Min.   :0.0000  
##  1st Qu.:-0.399   1st Qu.: 1.11   1st Qu.: -2.60   1st Qu.:0.0192  
##  Median :-0.020   Median : 3.97   Median : -0.13   Median :0.1240  
##  Mean   : 0.008   Mean   : 3.11   Mean   : -0.17   Mean   :0.2792  
##  3rd Qu.: 0.300   3rd Qu.: 5.44   3rd Qu.:  1.72   3rd Qu.:0.4653  
##  Max.   : 7.075   Max.   :18.59   Max.   : 62.44   Max.   :1.0000  
##    adj.P.Val            B        
##  Min.   :0.0170   Min.   :-8.29  
##  1st Qu.:0.0767   1st Qu.:-6.58  
##  Median :0.2479   Median :-5.50  
##  Mean   :0.3686   Mean   :-4.87  
##  3rd Qu.:0.6204   3rd Qu.:-3.50  
##  Max.   :1.0000   Max.   : 4.83
scatter_wt_mut <- extract_coefficient_scatter(limma_comparison, type="limma",
                                              x="wt30", y="wt120")
## This can do comparisons among the following columns in the pairwise result:
## wt120, wt30
## Actually comparing wt30 and wt120.
scatter_wt_mut$scatter

scatter_wt_mut$both_histogram$plot + ggplot2::scale_y_continuous(limits=c(0, 0.20))
## Warning: Removed 7039 rows containing non-finite values (stat_bin).
## Warning: Removed 7039 rows containing non-finite values (stat_density).
## Warning: Removed 1 rows containing missing values (geom_vline).

ma_wt_mut <- extract_de_plots(limma_comparison, type="limma")
ma_wt_mut$ma$plot

ma_wt_mut$volcano$plot

2.2 Then DESeq2

deseq_comparison <- sm(deseq2_pairwise(fun_data))

summary(deseq_comparison$all_tables$wt30_vs_wt120)
##     baseMean           logFC            lfcSE            stat        
##  Min.   :      0   Min.   :-5.615   Min.   :0.000   Min.   :-20.800  
##  1st Qu.:     28   1st Qu.:-0.386   1st Qu.:0.168   1st Qu.: -1.176  
##  Median :    192   Median : 0.000   Median :0.222   Median :  0.000  
##  Mean   :   1703   Mean   : 0.020   Mean   :0.489   Mean   :  0.168  
##  3rd Qu.:    536   3rd Qu.: 0.343   3rd Qu.:0.412   3rd Qu.:  1.108  
##  Max.   :4924000   Max.   : 7.212   Max.   :4.072   Max.   : 30.370  
##     P.Value         adj.P.Val     
##  Min.   :0.0000   Min.   :0.0000  
##  1st Qu.:0.0197   1st Qu.:0.0685  
##  Median :0.2503   Median :0.4676  
##  Mean   :0.3600   Mean   :0.4805  
##  3rd Qu.:0.6666   3rd Qu.:0.8732  
##  Max.   :1.0000   Max.   :1.0000
scatter_wt_mut <- extract_coefficient_scatter(deseq_comparison, type="deseq",
                                              x="wt30", y="wt120", gvis_filename=NULL)
## This can do comparisons among the following columns in the pairwise result:
## wt120, wt30, r2, r3
## Actually comparing wt30 and wt120.
scatter_wt_mut$scatter

plots_wt_mut <- extract_de_plots(deseq_comparison, type="deseq")
plots_wt_mut$ma$plot

plots_wt_mut$volcano$plot

2.3 EdgeR

edger_comparison <- sm(edger_pairwise(fun_data, model_batch=TRUE))

plots_wt_mut <- extract_de_plots(edger_comparison, type="edger")
scatter_wt_mut <- extract_coefficient_scatter(edger_comparison, type="edger",
                                              x="wt30", y="wt120", gvis_filename=NULL)
## This can do comparisons among the following columns in the pairwise result:
## wt120, wt30
## Actually comparing wt30 and wt120.
scatter_wt_mut$scatter

plots_wt_mut$ma$plot

plots_wt_mut$volcano$plot

2.4 EBSeq

{r simple_edger2 ebseq_comparison <- sm(ebseq_pairwise(fun_data)) head(ebseq_comparison$all_tables[[1]])

2.5 My stupid basic comparison

basic_comparison <- sm(basic_pairwise(fun_data))
summary(basic_comparison$all_tables$wt30_vs_wt120)
##  numerator_mean  denominator_mean numerator_var   denominator_var
##  Min.   :-2.20   Min.   :-3.20    Min.   :0.000   Min.   :0.000  
##  1st Qu.: 3.29   1st Qu.: 3.29    1st Qu.:0.019   1st Qu.:0.010  
##  Median : 4.63   Median : 4.63    Median :0.053   Median :0.028  
##  Mean   : 4.70   Mean   : 4.70    Mean   :0.134   Mean   :0.073  
##  3rd Qu.: 5.92   3rd Qu.: 5.93    3rd Qu.:0.134   3rd Qu.:0.074  
##  Max.   :18.61   Max.   :18.61    Max.   :9.509   Max.   :5.907  
##        t                p              logFC             adjp       
##  Min.   :-50.21   Min.   :0.0000   Min.   :-4.073   Min.   :0.0045  
##  1st Qu.: -2.10   1st Qu.:0.0327   1st Qu.:-0.399   1st Qu.:0.1307  
##  Median : -0.39   Median :0.1602   Median :-0.077   Median :0.3203  
##  Mean   : -0.16   Mean   :0.2766   Mean   : 0.000   Mean   :0.3876  
##  3rd Qu.:  1.53   3rd Qu.:0.4585   3rd Qu.: 0.278   3rd Qu.:0.6113  
##  Max.   : 49.10   Max.   :0.9996   Max.   : 7.084   Max.   :0.9996
scatter_wt_mut <- extract_coefficient_scatter(basic_comparison, type="basic",
                                              x="wt30", y="wt120")
## This can do comparisons among the following columns in the pairwise result:
## wt120, wt30
## Actually comparing wt30 and wt120.
scatter_wt_mut$scatter

plots_wt_mut <- extract_de_plots(basic_comparison, type="basic")
plots_wt_mut$ma$plot

plots_wt_mut$volcano$plot

2.6 Combine them all

all_comparisons <- sm(all_pairwise(fun_data, model_batch=TRUE, parallel=FALSE))

all_combined <- sm(combine_de_tables(all_comparisons, excel=FALSE))
head(all_combined$data[[1]], n=3)
##              deseq_logfc deseq_adjp edger_logfc edger_adjp limma_logfc
## SPAC1002.01     -1.08000     0.3664    -1.05900     0.2201    -0.99860
## SPAC1002.02     -0.01485     0.9816    -0.02342     1.0000     0.03778
## SPAC1002.03c    -0.22760     0.2327    -0.23630     0.1598    -0.33910
##              limma_adjp basic_nummed basic_denmed basic_numvar basic_denvar
## SPAC1002.01     0.16930        0.000        0.000     0.000000     0.000000
## SPAC1002.02     0.99460        2.860        2.856     0.360293     0.028898
## SPAC1002.03c    0.02432        6.916        7.252     0.002955     0.001016
##              basic_logfc  basic_t  basic_p basic_adjp deseq_basemean
## SPAC1002.01     0.000000  0.00000 0.000000    0.00000          11.15
## SPAC1002.02     0.004047  0.01124 0.991929    0.99611          87.42
## SPAC1002.03c   -0.336700 -9.25600 0.001969    0.03734        1621.00
##              deseq_lfcse deseq_stat deseq_p ebseq_fc ebseq_logfc ebseq_c1mean
## SPAC1002.01       0.8209   -1.31600  0.1882   0.5391    -0.89135        14.82
## SPAC1002.02       0.3316   -0.04479  0.9643   1.0571     0.08007        86.42
## SPAC1002.03c      0.1387   -1.64100  0.1008   0.8580    -0.22094      1763.03
##              ebseq_c2mean ebseq_mean ebseq_var ebseq_postfc ebseq_ppee
## SPAC1002.01         7.987      11.41     33.89       0.5554     0.4683
## SPAC1002.02        91.351      88.88    631.94       1.0567     0.9177
## SPAC1002.03c     1512.690    1637.86  36877.63       0.8581     0.6947
##              ebseq_ppde ebseq_adjp edger_logcpm edger_lr edger_p limma_ave
## SPAC1002.01     0.53174     0.4683      0.06691 2.745000 0.09757   -0.1955
## SPAC1002.02     0.08227     0.9177      2.89400 0.007429 0.93130    2.8470
## SPAC1002.03c    0.30531     0.6947      7.09500 3.399000 0.06522    7.0770
##               limma_t limma_b limma_p limma_adjp_ihw deseq_adjp_ihw
## SPAC1002.01   -2.8320 -4.0790 0.07147      1.000e+00      1.000e+00
## SPAC1002.02    0.1354 -7.4050 0.90140      1.000e+00      8.822e-01
## SPAC1002.03c -12.5400 -0.6495 0.00151      1.709e-02      2.626e-01
##              edger_adjp_ihw ebseq_adjp_ihw basic_adjp_ihw   lfc_meta   lfc_var
## SPAC1002.01       4.739e-01      1.000e+00      0.000e+00 -1.0520000 7.689e-04
## SPAC1002.02       9.141e-01      1.000e+00      1.000e+00  0.0007106 3.191e-03
## SPAC1002.03c      1.334e-01      2.918e-01      5.214e-03 -0.2681000 2.166e-03
##              lfc_varbymed    p_meta     p_var
## SPAC1002.01    -7.305e-04 1.191e-01 3.753e-03
## SPAC1002.02     4.491e+00 9.323e-01 9.899e-04
## SPAC1002.03c   -8.081e-03 5.584e-02 2.531e-03
sig_genes <- sm(extract_significant_genes(all_combined, excel=FALSE))
head(sig_genes$limma$ups[[1]], n=3)
##               deseq_logfc deseq_adjp edger_logfc edger_adjp limma_logfc
## SPBC2F12.09c        7.212  5.259e-66       7.170 1.264e-180       7.075
## SPAC22A12.17c       5.855  3.969e-19       5.822  3.155e-57       5.609
## SPAPB1A11.02        6.739  1.894e-06       6.483  1.257e-14       5.606
##               limma_adjp basic_nummed basic_denmed basic_numvar basic_denvar
## SPBC2F12.09c     0.01847        6.174      -0.9106      0.02211       0.5967
## SPAC22A12.17c    0.02447        9.396       3.6010      0.02236       0.9694
## SPAPB1A11.02     0.01696        1.648      -3.1970      0.68686       0.4981
##               basic_logfc basic_t  basic_p basic_adjp deseq_basemean
## SPBC2F12.09c        7.084  15.600 0.003004    0.04238          443.5
## SPAC22A12.17c       5.795  10.080 0.008325    0.06433         4289.0
## SPAPB1A11.02        4.844   7.708 0.001687    0.03455           21.2
##               deseq_lfcse deseq_stat   deseq_p ebseq_fc ebseq_logfc
## SPBC2F12.09c       0.4123     17.490 1.667e-68   143.63       7.166
## SPAC22A12.17c      0.6255      9.360 7.945e-21    52.82       5.723
## SPAPB1A11.02       1.2810      5.259 1.447e-07   103.34       6.691
##               ebseq_c1mean ebseq_c2mean ebseq_mean ebseq_var ebseq_postfc
## SPBC2F12.09c        6.2270       895.83     451.03 2.477e+05       132.23
## SPAC22A12.17c     161.9714      8556.19    4359.08 2.225e+07        52.65
## SPAPB1A11.02        0.4049        42.86      21.63 8.155e+02        45.38
##               ebseq_ppee ebseq_ppde ebseq_adjp edger_logcpm edger_lr    edger_p
## SPBC2F12.09c           0          1          0       5.2210   839.00 1.796e-184
## SPAC22A12.17c          0          1          0       8.4930   264.90  1.479e-59
## SPAPB1A11.02           0          0          0       0.9166    65.83  4.910e-16
##               limma_ave limma_t limma_b   limma_p limma_adjp_ihw deseq_adjp_ihw
## SPBC2F12.09c      2.592   19.36  0.8017 0.0004519      1.386e-02      4.625e-66
## SPAC22A12.17c     6.482   12.49 -0.3953 0.0015260      1.716e-02      3.792e-19
## SPAPB1A11.02     -1.192   27.66  0.2698 0.0001667      1.000e+00      7.571e-06
##               edger_adjp_ihw ebseq_adjp_ihw basic_adjp_ihw lfc_meta   lfc_var
## SPBC2F12.09c      1.076e-180      1.000e+00      1.263e-02    7.152 0.000e+00
## SPAC22A12.17c      2.516e-57      7.778e-01      1.865e-02    5.916 1.123e-01
## SPAPB1A11.02       1.989e-14      0.000e+00      6.937e-01    6.137 5.880e-02
##               lfc_varbymed    p_meta     p_var
## SPBC2F12.09c     0.000e+00 1.506e-04 6.807e-08
## SPAC22A12.17c    1.898e-02 5.087e-04 7.762e-07
## SPAPB1A11.02     9.581e-03 5.561e-05 9.255e-09
## Here we see that edger and deseq agree the least:
all_comparisons$comparison$comp
##                wt30_vs_wt120
## limma_vs_deseq        0.9808
## limma_vs_edger        0.9601
## limma_vs_ebseq        0.7944
## limma_vs_basic        0.9977
## deseq_vs_edger        0.9814
## deseq_vs_ebseq        0.8329
## deseq_vs_basic        0.9965
## edger_vs_ebseq        0.9165
## edger_vs_basic        0.9972
## ebseq_vs_basic        0.9950
## And here we can look at the set of 'significant' genes according to various tools:
yeast_sig <- sm(extract_significant_genes(all_combined, excel=FALSE))
yeast_barplots <- sm(significant_barplots(combined=all_combined))
yeast_barplots$limma

yeast_barplots$edger

yeast_barplots$deseq

2.6.1 Setting up

Since I didn’t acquire this data in a ‘normal’ way, I am going to post-generate a gff file which may be used by clusterprofiler, topgo, and gostats.

Therefore, I am going to make use of TxDb to make the requisite gff file.

limma_results <- limma_comparison$all_tables
## The set of comparisons performed
names(limma_results)
## [1] "wt30_vs_wt120"
table <- limma_results$wt30_vs_wt120
dim(table)
## [1] 7039    6
gene_names <- rownames(table)

updown_genes <- get_sig_genes(table, p=0.05, lfc=0.4, p_column="P.Value")
tt <- please_install("GenomicFeatures")
tt <- please_install("biomaRt")
available_marts <- biomaRt::listMarts(host="fungi.ensembl.org")
available_marts
##            biomart                     version
## 1       fungi_mart      Ensembl Fungi Genes 48
## 2 fungi_variations Ensembl Fungi Variations 48
ensembl_mart <- biomaRt::useMart("fungi_mart", host="fungi.ensembl.org")
available_datasets <- biomaRt::listDatasets(ensembl_mart)
pombe_hit <- grep(pattern="pombe", x=available_datasets[["description"]])
pombe_name <- available_datasets[pombe_hit, "dataset"]
pombe_mart <- biomaRt::useDataset(pombe_name, mart=ensembl_mart)

pombe_goids <- biomaRt::getBM(attributes=c("pombase_transcript", "go_id"),
                              values=gene_names, mart=pombe_mart)
colnames(pombe_goids) <- c("ID", "GO")

2.6.2 Setting up with hpgltools

The above worked, it provided a table of ID and ontology. It was however a bit fraught. Here is another way.

## In theory, the above should work with a single function call:
pombe_goids_simple <- load_biomart_go(species="spombe", overwrite=TRUE,
                                      dl_rows=c("pombase_transcript", "go_id"),
                                      host="fungi.ensembl.org")
## Unable to perform useMart, perhaps the host/mart is incorrect: fungi.ensembl.org ENSEMBL_MART_ENSEMBL.
## The available marts are:
## fungi_martfungi_variations
## Trying the first one.
## Unable to perform useDataset, perhaps the given dataset is incorrect: spombe_gene_ensembl.
## Trying instead to use the dataset: spombe_eg_gene
## That seems to have worked, extracting the resulting annotations.
## Finished downloading ensembl go annotations, saving to spombe_go_annotations.rda.
## Saving ontologies to spombe_go_annotations.rda.
## Finished save().
head(pombe_goids_simple[["go"]])
##               ID         GO
## 1    SPRRNA.50.1           
## 2 SPNCRNA.1095.1           
## 3   SPAC212.11.1 GO:0000784
## 4   SPAC212.11.1 GO:0005634
## 5   SPAC212.11.1 GO:0000166
## 6   SPAC212.11.1 GO:0005524
head(pombe_goids)
##               ID         GO
## 1    SPRRNA.50.1           
## 2 SPNCRNA.1095.1           
## 3   SPAC212.11.1 GO:0000784
## 4   SPAC212.11.1 GO:0005634
## 5   SPAC212.11.1 GO:0000166
## 6   SPAC212.11.1 GO:0005524
## This used to work, but does so no longer and I do not know why.
## pombe <- sm(GenomicFeatures::makeTxDbFromBiomart(biomart="fungal_mart",
##                                                  dataset="spombe_eg_gene",
##                                                  host="fungi.ensembl.org"))

## I bet I can get all this information from ensembl now.
## This was found at the bottom of: https://www.biostars.org/p/232005/
link <- "ftp://ftp.ensemblgenomes.org/pub/release-34/fungi/gff3/schizosaccharomyces_pombe/Schizosaccharomyces_pombe.ASM294v2.34.gff3.gz"
pombe <- GenomicFeatures::makeTxDbFromGFF(link, format="gff3", organism="Schizosaccharomyces pombe",
                                          taxonomyId=4896)
## Import genomic features from the file as a GRanges object ...
## OK
## Prepare the 'metadata' data frame ... OK
## Make the TxDb object ... OK
pombe_transcripts <- as.data.frame(GenomicFeatures::transcriptsBy(pombe))
lengths <- pombe_transcripts[, c("group_name","width")]
colnames(lengths) <- c("ID","width")
## Something useful I didn't notice before:
## makeTranscriptDbFromGFF()  ## From GenomicFeatures, much like my own gff2df()
gff_from_txdb <- GenomicFeatures::asGFF(pombe)
## why is GeneID: getting prefixed to the IDs!?
gff_from_txdb$ID <- gsub(x=gff_from_txdb$ID, pattern="GeneID:", replacement="")
written_gff <- rtracklayer::export.gff3(gff_from_txdb, con="pombe.gff")
## Warning in .local(object, con, format, ...): The phase information is missing. The written file will contain CDS
##   with no phase information.

2.7 GOSeq test

summary(updown_genes)
##            Length Class      Mode
## up_genes   6      data.frame list
## down_genes 6      data.frame list
test_genes <- updown_genes$down_genes
rownames(test_genes) <- paste0(rownames(test_genes), ".1")
lengths$ID <- paste0(lengths$ID, ".1")
goseq_result <- sm(simple_goseq(sig_genes=test_genes, go_db=pombe_goids, length_db=lengths))

head(goseq_result$alldata)
## NULL
goseq_result$pvalue_plots$mfp_plot

test_genes <- updown_genes$up_genes
rownames(test_genes) <- paste0(rownames(test_genes), ".1")
goseq_result <- sm(simple_goseq(sig_genes=test_genes, go_db=pombe_goids, length_db=lengths))

head(goseq_result$all_data)
##       category over_represented_pvalue under_represented_pvalue numDEInCat
## 643 GO:0008150               4.739e-48                        1        116
## 384 GO:0005829               7.894e-47                        1        120
## 353 GO:0005737               2.788e-46                        1        118
## 344 GO:0005634               1.047e-45                        1        121
## 137 GO:0003674               4.076e-42                        1        109
## 854 GO:0016020               9.518e-40                        1         97
##     numInCat               term ontology    qvalue
## 643      517 biological_process       BP 8.207e-45
## 384      551            cytosol       CC 6.836e-44
## 353      535          cytoplasm       CC 1.610e-43
## 344      576            nucleus       CC 4.532e-43
## 137      514 molecular_function       MF 1.412e-39
## 854      415           membrane       CC 2.747e-37
goseq_result$pvalue_plots$bpp_plot

2.8 ClusterProfiler test

clusterProfiler really prefers an orgdb instance to use, which is probably smart, as they are pretty nice. Sadly, there is no pre-defined orgdb for pombe…

## holy crap makeOrgPackageFromNCBI is slow, no slower than some of mine, so who am I to complain.
orgdb <- AnnotationForge::makeOrgPackageFromNCBI(
                            version="0.1", author="atb <abelew@gmail.com>",
                            maintainer="atb <abelew@gmail.com>", tax_id="4896",
                            genus="Schizosaccharomyces", species="pombe")
## This created the directory 'org.spombe.eg.db'
devtools::install_local("org.Spombe.eg.db")
library(org.Spombe.eg.db)
## Don't forget to remove the terminal .1 from the gene names...
## If you do forget this, it will fail for no easily visible reason until you remember
## this and get really mad at yourself.
rownames(test_genes) <- gsub(pattern=".1$", replacement="", x=rownames(test_genes))
pombe_goids[["ID"]] <- gsub(pattern=".1$", replacement="", x=pombe_goids[["ID"]])
cp_result <- simple_clusterprofiler(sig_genes=test_genes, do_david=FALSE, do_gsea=FALSE,
                                    de_table=all_combined$data[[1]],
                                    orgdb=org.Spombe.eg.db, orgdb_to="ALIAS")
cp_result[["pvalue_plots"]][["ego_all_mf"]]
## Yay bar plots!
## Get rid of those stupid terminal .1s.
rownames(test_genes) <- gsub(pattern=".1$", replacement="", x=rownames(test_genes))
pombe_goids[["ID"]] <- gsub(pattern=".1$", replacement="", x=pombe_goids[["ID"]])
tp_result <- sm(simple_topgo(sig_genes=test_genes, go_db=pombe_goids, pval_column="limma_adjp"))

tp_result[["pvalue_plots"]][["mfp_plot_over"]]

tp_result[["pvalue_plots"]][["bpp_plot_over"]]

## Get rid of those stupid terminal .1s.
##rownames(test_genes) <- gsub(pattern=".1$", replacement="", x=rownames(test_genes))
pombe_goids[["ID"]] <- gsub(pattern=".1$", replacement="", x=pombe_goids[["ID"]])
## universe_merge is the column in the final data frame when.
## gff_type is the field in the gff file providing the id, this may be redundant with
## universe merge, that is something to check on...
gst_result <- sm(simple_gostats(sig_genes=test_genes, go_db=pombe_goids, universe_merge="id",
                                gff_type="gene",
                                gff="pombe.gff", pval_column="limma_adjp"))
gst_result[["pvalue_plots"]][["mfp_plot_over"]]

gst_result[["pvalue_plots"]][["bpp_plot_over"]]

pander::pander(sessionInfo())

R version 4.0.3 (2020-10-10)

Platform: x86_64-pc-linux-gnu (64-bit)

locale: LC_CTYPE=en_US.UTF-8, LC_NUMERIC=C, LC_TIME=en_US.UTF-8, LC_COLLATE=en_US.UTF-8, LC_MONETARY=en_US.UTF-8, LC_MESSAGES=en_US.UTF-8, LC_PAPER=en_US.UTF-8, LC_NAME=C, LC_ADDRESS=C, LC_TELEPHONE=C, LC_MEASUREMENT=en_US.UTF-8 and LC_IDENTIFICATION=C

attached base packages: splines, stats4, parallel, stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: GO.db(v.3.12.1), AnnotationDbi(v.1.52.0), GOstats(v.2.56.0), edgeR(v.3.32.0), lme4(v.1.1-25), Matrix(v.1.2-18), BiocParallel(v.1.24.1), variancePartition(v.1.20.0), fission(v.1.10.0), ruv(v.0.9.7.1), SummarizedExperiment(v.1.20.0), GenomicRanges(v.1.42.0), GenomeInfoDb(v.1.26.1), IRanges(v.2.24.0), S4Vectors(v.0.28.0), MatrixGenerics(v.1.2.0), matrixStats(v.0.57.0), hpgltools(v.1.0), R6(v.2.5.0), Biobase(v.2.50.0) and BiocGenerics(v.0.36.0)

loaded via a namespace (and not attached): R.utils(v.2.10.1), tidyselect(v.1.1.0), RSQLite(v.2.2.1), htmlwidgets(v.1.5.2), grid(v.4.0.3), Rtsne(v.0.15), devtools(v.2.3.2), IHW(v.1.16.0), DESeq(v.1.39.0), munsell(v.0.5.0), codetools(v.0.2-18), preprocessCore(v.1.52.0), statmod(v.1.4.35), withr(v.2.3.0), colorspace(v.2.0-0), Category(v.2.56.0), highr(v.0.8), knitr(v.1.30), rstudioapi(v.0.13), Vennerable(v.3.1.0.9000), robustbase(v.0.93-6), genoPlotR(v.0.8.9), labeling(v.0.4.2), slam(v.0.1-47), GenomeInfoDbData(v.1.2.4), lpsymphony(v.1.18.0), topGO(v.2.42.0), bit64(v.4.0.5), farver(v.2.0.3), rprojroot(v.2.0.2), vctrs(v.0.3.5), generics(v.0.1.0), xfun(v.0.19), BiocFileCache(v.1.14.0), fastcluster(v.1.1.25), doParallel(v.1.0.16), locfit(v.1.5-9.4), bitops(v.1.0-6), DelayedArray(v.0.16.0), assertthat(v.0.2.1), scales(v.1.1.1), gtable(v.0.3.0), sva(v.3.38.0), processx(v.3.4.4), rlang(v.0.4.8), genefilter(v.1.72.0), rtracklayer(v.1.50.0), lazyeval(v.0.2.2), selectr(v.0.4-2), yaml(v.2.2.1), reshape2(v.1.4.4), GenomicFeatures(v.1.42.1), crosstalk(v.1.1.0.1), qvalue(v.2.22.0), RBGL(v.1.66.0), tools(v.4.0.3), usethis(v.1.6.3), ggplot2(v.3.3.2), ellipsis(v.0.3.1), gplots(v.3.1.0), RColorBrewer(v.1.1-2), blockmodeling(v.1.0.0), sessioninfo(v.1.1.1), Rcpp(v.1.0.5), plyr(v.1.8.6), progress(v.1.2.2), zlibbioc(v.1.36.0), purrr(v.0.3.4), RCurl(v.1.98-1.2), BiasedUrn(v.1.07), ps(v.1.4.0), prettyunits(v.1.1.1), openssl(v.1.4.3), ggrepel(v.0.8.2), colorRamps(v.2.3), fs(v.1.5.0), magrittr(v.2.0.1), data.table(v.1.13.2), openxlsx(v.4.2.3), SparseM(v.1.78), goseq(v.1.42.0), pkgload(v.1.1.0), hms(v.0.5.3), evaluate(v.0.14), xtable(v.1.8-4), pbkrtest(v.0.4-8.6), XML(v.3.99-0.5), gridExtra(v.2.3), testthat(v.3.0.0), compiler(v.4.0.3), biomaRt(v.2.46.0), tibble(v.3.0.4), KernSmooth(v.2.23-18), crayon(v.1.3.4), minqa(v.1.2.4), R.oo(v.1.24.0), htmltools(v.0.5.0), mgcv(v.1.8-33), corpcor(v.1.6.9), tidyr(v.1.1.2), geneplotter(v.1.68.0), DBI(v.1.1.0), geneLenDataBase(v.1.26.0), dbplyr(v.2.0.0), MASS(v.7.3-53), rappdirs(v.0.3.1), boot(v.1.3-25), ade4(v.1.7-16), readr(v.1.4.0), cli(v.2.2.0), quadprog(v.1.5-8), R.methodsS3(v.1.8.1), pkgconfig(v.2.0.3), GenomicAlignments(v.1.26.0), plotly(v.4.9.2.1), xml2(v.1.3.2), foreach(v.1.5.1), annotate(v.1.68.0), XVector(v.0.30.0), AnnotationForge(v.1.32.0), rvest(v.0.3.6), EBSeq(v.1.30.0), stringr(v.1.4.0), callr(v.3.5.1), digest(v.0.6.27), graph(v.1.68.0), Biostrings(v.2.58.0), rmarkdown(v.2.5), GSEABase(v.1.52.0), directlabels(v.2020.6.17), curl(v.4.3), Rsamtools(v.2.6.0), gtools(v.3.8.2), nloptr(v.1.2.2.2), lifecycle(v.0.2.0), nlme(v.3.1-150), jsonlite(v.1.7.1), desc(v.1.2.0), viridisLite(v.0.3.0), askpass(v.1.1), limma(v.3.46.0), fansi(v.0.4.1), pillar(v.1.4.7), lattice(v.0.20-41), httr(v.1.4.2), DEoptimR(v.1.0-8), pkgbuild(v.1.1.0), survival(v.3.2-7), glue(v.1.4.2), remotes(v.2.2.0), zip(v.2.1.1), fdrtool(v.1.2.15), iterators(v.1.0.13), Rgraphviz(v.2.34.0), pander(v.0.6.3), bit(v.4.0.4), stringi(v.1.5.3), blob(v.1.2.1), DESeq2(v.1.30.0), caTools(v.1.18.0), memoise(v.1.1.0) and dplyr(v.1.0.2)

LS0tCnRpdGxlOiAiaHBnbHRvb2xzIERpZmZlcmVudGlhbCBFeHByZXNzaW9uIEFuYWx5c2VzIFVzaW5nIHRoZSBGaXNzaW9uIERhdGFzZXQiCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICAgY29sbGFwc2VkOiBmYWxzZQogICAgc21vb3RoX3Njcm9sbDogZmFsc2UKdmlnbmV0dGU6ID4KICAlXFZpZ25ldHRlSW5kZXhFbnRyeXtjLTAzX2Zpc3Npb25fZGlmZmVyZW50aWFsX2V4cHJlc3Npb259CiAgJVxWaWduZXR0ZUVuZ2luZXtrbml0cjo6cm1hcmtkb3dufQogIFx1c2VwYWNrYWdlW3V0Zjhde2lucHV0ZW5jfQotLS0KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CiMjIFRoZXNlIGFyZSB0aGUgb3B0aW9ucyBJIHRlbmQgdG8gZmF2b3IKbGlicmFyeSgiaHBnbHRvb2xzIikKIyMgdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGg9OTAsCiAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGg9OCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9OCwKICAgICAgICAgICAgICAgICAgICAgIGRwaT05NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHM9NCwKICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbD0iYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplPTEwKSkKc2V0LnNlZWQoMSkKcm1kX2ZpbGUgPC0gImMtMDNfZmlzc2lvbl9kaWZmZXJlbnRpYWxfZXhwcmVzc2lvbi5SbWQiCmBgYAoKIyBFeGFtcGxlIGhwZ2x0b29sIHVzYWdlIHdpdGggYSByZWFsIGRhdGEgc2V0IChmaXNzaW9uKQoKVGhpcyBkb2N1bWVudCBhaW1zIHRvIHByb3ZpZGUgZnVydGhlciBleGFtcGxlcyBpbiBob3cgdG8gdXNlIHRoZSBocGdsdG9vbHMuCgpOb3RlIHRvIHNlbGYsIHRoZSBoZWFkZXIgaGFzIHJtYXJrZG93bjo6cGRmX2RvY3VtZW50IGluc3RlYWQgb2YgaHRtbF9kb2N1bWVudCBvciBodG1sX3ZpZ25ldHRlCmJlY2F1c2UgaXQgZ2V0cyBzb21lIGJ1bGxjcmFwIGVycm9yICdtYXJnaW5zIHRvbyBsYXJnZScuLi4KCiMjIFNldHRpbmcgdXAKCkhlcmUgYXJlIHRoZSBjb21tYW5kcyBJIGludm9rZSB0byBnZXQgcmVhZHkgdG8gcGxheSB3aXRoIG5ldyBkYXRhLCBpbmNsdWRpbmcgZXZlcnl0aGluZwpyZXF1aXJlZCB0byBpbnN0YWxsIGhwZ2x0b29scywgdGhlIHNvZnR3YXJlIGl0IHVzZXMsIGFuZCB0aGUgZmlzc2lvbiBkYXRhLgoKYGBge3Igc2V0dXB9CmxpYnJhcnkoaHBnbHRvb2xzKQp0dCA8LSBzbShsaWJyYXJ5KGZpc3Npb24pKQp0dCA8LSBkYXRhKGZpc3Npb24pCmBgYAoKIyMgQW5ub3RhdGlvbiBjb2xsZWN0aW9uCgpMYXRlciBvbiBpbiB0aGlzLCBJIHdpbGwgZG8gc29tZSBvbnRvbG9neSBzaGVuYW5pZ2Fucy4gIEJ1dCBJIGNhbiBncmFiIHNvbWUKYW5ub3RhdGlvbnMgZnJvbSBiaW9tYXJ0IG5vdy4KCmBgYHtyIHNwb21iZV9hbm5vdGF0aW9uc30KcG9tYmVfYW5ub3RhdGlvbnMgPC0gc20obG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKAogIGhvc3Q9ImZ1bmdpLmVuc2VtYmwub3JnIiwKICB0cnltYXJ0PSJmdW5nYWxfbWFydCIsCiAgdHJ5ZGF0YXNldD0ic3BvbWJlX2VnX2dlbmUiLAogIGdlbmVfcmVxdWVzdHM9YygicG9tYmFzZV90cmFuc2NyaXB0IiwgImVuc2VtYmxfZ2VuZV9pZCIsICJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiLAogICAgICAgICAgICAgICAgICAiaGduY19zeW1ib2wiLCAiZGVzY3JpcHRpb24iLCAiZ2VuZV9iaW90eXBlIiksCiAgc3BlY2llcz0ic3BvbWJlIiwgb3ZlcndyaXRlPVRSVUUpKQpwb21iZV9tYXJ0IDwtIHBvbWJlX2Fubm90YXRpb25zW1sibWFydCJdXQphbm5vdGF0aW9ucyA8LSBwb21iZV9hbm5vdGF0aW9uc1tbImFubm90YXRpb24iXV0Kcm93bmFtZXMoYW5ub3RhdGlvbnMpIDwtIG1ha2UubmFtZXMoZ3N1YihwYXR0ZXJuPSJcXC5cXGQrJCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQ9IiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD1yb3duYW1lcyhhbm5vdGF0aW9ucykpLCB1bmlxdWU9VFJVRSkKYGBgCgojIyBEYXRhIGltcG9ydAoKQWxsIHRoZSB3b3JrIEkgZG8gaW4gRHIuIEVsLVNheWVkJ3MgbGFiIG1ha2VzIHNvbWUgcHJldHR5IGhhcmQKYXNzdW1wdGlvbnMgYWJvdXQgaG93IGRhdGEgaXMgc3RvcmVkLiAgQXMgYSByZXN1bHQsIHRvIHVzZSB0aGUgZmlzc2lvbgpkYXRhIHNldCBJIHdpbGwgZG8gYSBsaXR0bGUgYml0IG9mIHNoZW5hbmlnYW5zIHRvIG1hdGNoIGl0IHRvIHRoZQpleHBlY3RlZCBmb3JtYXQuICBOb3cgdGhhdCBJIGhhdmUgcGxheWVkIGEgbGl0dGxlIHdpdGggZmlzc2lvbiwgSQp0aGluayBpdHMgZm9ybWF0IGlzIHF1aXRlIG5pY2UgYW5kIGFtIGxpa2VseSB0byBoYXZlIG15IGV4cGVyaW1lbnQKY2xhc3MgaW5zdGVhZCBiZSBhIFN1bW1hcml6ZWRFeHBlcmltZW50LgoKYGBge3IgZGF0YV9pbXBvcnR9CiMjIEV4dHJhY3QgdGhlIG1ldGEgZGF0YSBmcm9tIHRoZSBmaXNzaW9uIGRhdGFzZXQKbWV0YSA8LSBhcy5kYXRhLmZyYW1lKGZpc3Npb25AY29sRGF0YSkKIyMgTWFrZSBjb25kaXRpb25zIGFuZCBiYXRjaGVzCm1ldGEkY29uZGl0aW9uIDwtIHBhc3RlKG1ldGEkc3RyYWluLCBtZXRhJG1pbnV0ZSwgc2VwPSIuIikKbWV0YSRiYXRjaCA8LSBtZXRhJHJlcGxpY2F0ZQptZXRhJHNhbXBsZS5pZCA8LSByb3duYW1lcyhtZXRhKQojIyBHcmFiIHRoZSBjb3VudCBkYXRhCmZpc3Npb25fZGF0YSA8LSBmaXNzaW9uQGFzc2F5cyRkYXRhJGNvdW50cwojIyBUaGlzIHdpbGwgbWFrZSBhbiBleHBlcmltZW50IHN1cGVyY2xhc3MgY2FsbGVkICdleHB0JyBhbmQgaXQgY29udGFpbnMKIyMgYW4gRXhwcmVzc2lvblNldCBhbG9uZyB3aXRoIGFueSBhcmJpdHJhcnkgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbmUgbWlnaHQgd2FudCB0byBpbmNsdWRlLgojIyBBbG9uZyB0aGUgd2F5IGl0IHdyaXRlcyBhIFJkYXRhIGZpbGUgd2hpY2ggaXMgYnkgZGVmYXVsdCBjYWxsZWQgJ2V4cHQuUmRhdGEnCmZpc3Npb25fZXhwdCA8LSBjcmVhdGVfZXhwdChtZXRhZGF0YT1tZXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnRfZGF0YWZyYW1lPWZpc3Npb25fZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbz1hbm5vdGF0aW9ucykKYGBgCgojIFNvbWUgc2ltcGxlIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2VzCgpUcmF2aXMgd2lzZWx5IGltcG9zZXMgYSBsaW1pdCBvbiB0aGUgYW1vdW50IG9mIHRpbWUgZm9yIGJ1aWxkaW5nIHZpZ25ldHRlcy4KTXkgdG9vbHMgYnkgZGVmYXVsdCB3aWxsIGF0dGVtcHQgYWxsIHBvc3NpYmxlIHBhaXJ3aXNlIGNvbXBhcmlzb25zLCB3aGljaCB0YWtlcyBhIGxvbmcgdGltZS4KVGhlcmVmb3JlIEkgYW0gZ29pbmcgdG8gdGFrZSBhIHN1YnNldCBvZiB0aGUgZGF0YSBhbmQgbGltaXQgdGhlc2UgY29tcGFyaXNvbnMgdG8gdGhhdC4KCmBgYHtyIHNpbXBsZV9zdWJzZXR9CmZ1bl9kYXRhIDwtIHN1YnNldF9leHB0KGZpc3Npb25fZXhwdCwKICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0PSJjb25kaXRpb249PSd3dC4xMjAnfGNvbmRpdGlvbj09J3d0LjMwJyIpCmZ1bl9maWx0IDwtIG5vcm1hbGl6ZV9leHB0KGZ1bl9kYXRhLCBmaWx0ZXI9InNpbXBsZSIpCmZ1bl9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGZ1bl9maWx0LCBiYXRjaD0ibGltbWEiLCBub3JtPSJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIpKQpgYGAKCiMjIFRyeSB1c2luZyBsaW1tYSBmaXJzdAoKYGBge3Igc2ltcGxlX2xpbW1hfQpsaW1tYV9jb21wYXJpc29uIDwtIHNtKGxpbW1hX3BhaXJ3aXNlKGZ1bl9kYXRhKSkKbmFtZXMobGltbWFfY29tcGFyaXNvbiRhbGxfdGFibGVzKQpzdW1tYXJ5KGxpbW1hX2NvbXBhcmlzb24kYWxsX3RhYmxlcyR3dDMwX3ZzX3d0MTIwKQpzY2F0dGVyX3d0X211dCA8LSBleHRyYWN0X2NvZWZmaWNpZW50X3NjYXR0ZXIobGltbWFfY29tcGFyaXNvbiwgdHlwZT0ibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD0id3QzMCIsIHk9Ind0MTIwIikKc2NhdHRlcl93dF9tdXQkc2NhdHRlcgpzY2F0dGVyX3d0X211dCRib3RoX2hpc3RvZ3JhbSRwbG90ICsgZ2dwbG90Mjo6c2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKDAsIDAuMjApKQptYV93dF9tdXQgPC0gZXh0cmFjdF9kZV9wbG90cyhsaW1tYV9jb21wYXJpc29uLCB0eXBlPSJsaW1tYSIpCm1hX3d0X211dCRtYSRwbG90Cm1hX3d0X211dCR2b2xjYW5vJHBsb3QKYGBgCgojIyBUaGVuIERFU2VxMgoKYGBge3Igc2ltcGxlX2Rlc2VxMn0KZGVzZXFfY29tcGFyaXNvbiA8LSBzbShkZXNlcTJfcGFpcndpc2UoZnVuX2RhdGEpKQpzdW1tYXJ5KGRlc2VxX2NvbXBhcmlzb24kYWxsX3RhYmxlcyR3dDMwX3ZzX3d0MTIwKQpzY2F0dGVyX3d0X211dCA8LSBleHRyYWN0X2NvZWZmaWNpZW50X3NjYXR0ZXIoZGVzZXFfY29tcGFyaXNvbiwgdHlwZT0iZGVzZXEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD0id3QzMCIsIHk9Ind0MTIwIiwgZ3Zpc19maWxlbmFtZT1OVUxMKQpzY2F0dGVyX3d0X211dCRzY2F0dGVyCnBsb3RzX3d0X211dCA8LSBleHRyYWN0X2RlX3Bsb3RzKGRlc2VxX2NvbXBhcmlzb24sIHR5cGU9ImRlc2VxIikKcGxvdHNfd3RfbXV0JG1hJHBsb3QKcGxvdHNfd3RfbXV0JHZvbGNhbm8kcGxvdApgYGAKCiMjIEVkZ2VSCgpgYGB7ciBzaW1wbGVfZWRnZXIxfQplZGdlcl9jb21wYXJpc29uIDwtIHNtKGVkZ2VyX3BhaXJ3aXNlKGZ1bl9kYXRhLCBtb2RlbF9iYXRjaD1UUlVFKSkKcGxvdHNfd3RfbXV0IDwtIGV4dHJhY3RfZGVfcGxvdHMoZWRnZXJfY29tcGFyaXNvbiwgdHlwZT0iZWRnZXIiKQpzY2F0dGVyX3d0X211dCA8LSBleHRyYWN0X2NvZWZmaWNpZW50X3NjYXR0ZXIoZWRnZXJfY29tcGFyaXNvbiwgdHlwZT0iZWRnZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD0id3QzMCIsIHk9Ind0MTIwIiwgZ3Zpc19maWxlbmFtZT1OVUxMKQpzY2F0dGVyX3d0X211dCRzY2F0dGVyCnBsb3RzX3d0X211dCRtYSRwbG90CnBsb3RzX3d0X211dCR2b2xjYW5vJHBsb3QKYGBgCgojIyBFQlNlcQoKYGBge3Igc2ltcGxlX2VkZ2VyMgplYnNlcV9jb21wYXJpc29uIDwtIHNtKGVic2VxX3BhaXJ3aXNlKGZ1bl9kYXRhKSkKaGVhZChlYnNlcV9jb21wYXJpc29uJGFsbF90YWJsZXNbWzFdXSkKYGBgCgojIyBNeSBzdHVwaWQgYmFzaWMgY29tcGFyaXNvbgoKYGBge3Igc2ltcGxlX2Jhc2ljfQpiYXNpY19jb21wYXJpc29uIDwtIHNtKGJhc2ljX3BhaXJ3aXNlKGZ1bl9kYXRhKSkKc3VtbWFyeShiYXNpY19jb21wYXJpc29uJGFsbF90YWJsZXMkd3QzMF92c193dDEyMCkKc2NhdHRlcl93dF9tdXQgPC0gZXh0cmFjdF9jb2VmZmljaWVudF9zY2F0dGVyKGJhc2ljX2NvbXBhcmlzb24sIHR5cGU9ImJhc2ljIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9Ind0MzAiLCB5PSJ3dDEyMCIpCnNjYXR0ZXJfd3RfbXV0JHNjYXR0ZXIKcGxvdHNfd3RfbXV0IDwtIGV4dHJhY3RfZGVfcGxvdHMoYmFzaWNfY29tcGFyaXNvbiwgdHlwZT0iYmFzaWMiKQpwbG90c193dF9tdXQkbWEkcGxvdApwbG90c193dF9tdXQkdm9sY2FubyRwbG90CmBgYAoKIyMgQ29tYmluZSB0aGVtIGFsbAoKYGBge3Igc2ltcGxlX2FsbH0KYWxsX2NvbXBhcmlzb25zIDwtIHNtKGFsbF9wYWlyd2lzZShmdW5fZGF0YSwgbW9kZWxfYmF0Y2g9VFJVRSwgcGFyYWxsZWw9RkFMU0UpKQphbGxfY29tYmluZWQgPC0gc20oY29tYmluZV9kZV90YWJsZXMoYWxsX2NvbXBhcmlzb25zLCBleGNlbD1GQUxTRSkpCmhlYWQoYWxsX2NvbWJpbmVkJGRhdGFbWzFdXSwgbj0zKQpzaWdfZ2VuZXMgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhhbGxfY29tYmluZWQsIGV4Y2VsPUZBTFNFKSkKaGVhZChzaWdfZ2VuZXMkbGltbWEkdXBzW1sxXV0sIG49MykKCiMjIEhlcmUgd2Ugc2VlIHRoYXQgZWRnZXIgYW5kIGRlc2VxIGFncmVlIHRoZSBsZWFzdDoKYWxsX2NvbXBhcmlzb25zJGNvbXBhcmlzb24kY29tcAoKIyMgQW5kIGhlcmUgd2UgY2FuIGxvb2sgYXQgdGhlIHNldCBvZiAnc2lnbmlmaWNhbnQnIGdlbmVzIGFjY29yZGluZyB0byB2YXJpb3VzIHRvb2xzOgp5ZWFzdF9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhhbGxfY29tYmluZWQsIGV4Y2VsPUZBTFNFKSkKeWVhc3RfYmFycGxvdHMgPC0gc20oc2lnbmlmaWNhbnRfYmFycGxvdHMoY29tYmluZWQ9YWxsX2NvbWJpbmVkKSkKeWVhc3RfYmFycGxvdHMkbGltbWEKeWVhc3RfYmFycGxvdHMkZWRnZXIKeWVhc3RfYmFycGxvdHMkZGVzZXEKYGBgCgojIyMgU2V0dGluZyB1cAoKU2luY2UgSSBkaWRuJ3QgYWNxdWlyZSB0aGlzIGRhdGEgaW4gYSAnbm9ybWFsJyB3YXksIEkgYW0gZ29pbmcgdG8gcG9zdC1nZW5lcmF0ZSBhCmdmZiBmaWxlIHdoaWNoIG1heSBiZSB1c2VkIGJ5IGNsdXN0ZXJwcm9maWxlciwgdG9wZ28sIGFuZCBnb3N0YXRzLgoKVGhlcmVmb3JlLCBJIGFtIGdvaW5nIHRvIG1ha2UgdXNlIG9mIFR4RGIgdG8gbWFrZSB0aGUgcmVxdWlzaXRlIGdmZiBmaWxlLgoKYGBge3Igb250b2xvZ3lfc2V0dXB9CmxpbW1hX3Jlc3VsdHMgPC0gbGltbWFfY29tcGFyaXNvbiRhbGxfdGFibGVzCiMjIFRoZSBzZXQgb2YgY29tcGFyaXNvbnMgcGVyZm9ybWVkCm5hbWVzKGxpbW1hX3Jlc3VsdHMpCnRhYmxlIDwtIGxpbW1hX3Jlc3VsdHMkd3QzMF92c193dDEyMApkaW0odGFibGUpCmdlbmVfbmFtZXMgPC0gcm93bmFtZXModGFibGUpCgp1cGRvd25fZ2VuZXMgPC0gZ2V0X3NpZ19nZW5lcyh0YWJsZSwgcD0wLjA1LCBsZmM9MC40LCBwX2NvbHVtbj0iUC5WYWx1ZSIpCnR0IDwtIHBsZWFzZV9pbnN0YWxsKCJHZW5vbWljRmVhdHVyZXMiKQp0dCA8LSBwbGVhc2VfaW5zdGFsbCgiYmlvbWFSdCIpCmF2YWlsYWJsZV9tYXJ0cyA8LSBiaW9tYVJ0OjpsaXN0TWFydHMoaG9zdD0iZnVuZ2kuZW5zZW1ibC5vcmciKQphdmFpbGFibGVfbWFydHMKZW5zZW1ibF9tYXJ0IDwtIGJpb21hUnQ6OnVzZU1hcnQoImZ1bmdpX21hcnQiLCBob3N0PSJmdW5naS5lbnNlbWJsLm9yZyIpCmF2YWlsYWJsZV9kYXRhc2V0cyA8LSBiaW9tYVJ0OjpsaXN0RGF0YXNldHMoZW5zZW1ibF9tYXJ0KQpwb21iZV9oaXQgPC0gZ3JlcChwYXR0ZXJuPSJwb21iZSIsIHg9YXZhaWxhYmxlX2RhdGFzZXRzW1siZGVzY3JpcHRpb24iXV0pCnBvbWJlX25hbWUgPC0gYXZhaWxhYmxlX2RhdGFzZXRzW3BvbWJlX2hpdCwgImRhdGFzZXQiXQpwb21iZV9tYXJ0IDwtIGJpb21hUnQ6OnVzZURhdGFzZXQocG9tYmVfbmFtZSwgbWFydD1lbnNlbWJsX21hcnQpCgpwb21iZV9nb2lkcyA8LSBiaW9tYVJ0OjpnZXRCTShhdHRyaWJ1dGVzPWMoInBvbWJhc2VfdHJhbnNjcmlwdCIsICJnb19pZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9Z2VuZV9uYW1lcywgbWFydD1wb21iZV9tYXJ0KQpjb2xuYW1lcyhwb21iZV9nb2lkcykgPC0gYygiSUQiLCAiR08iKQpgYGAKCiMjIyBTZXR0aW5nIHVwIHdpdGggaHBnbHRvb2xzCgpUaGUgYWJvdmUgd29ya2VkLCBpdCBwcm92aWRlZCBhIHRhYmxlIG9mIElEIGFuZCBvbnRvbG9neS4gIEl0IHdhcyBob3dldmVyIGEgYml0IGZyYXVnaHQuCkhlcmUgaXMgYW5vdGhlciB3YXkuCgpgYGB7ciBvbnRvbG9neV9zZXR1cF9ocGdsdG9vbHN9CiMjIEluIHRoZW9yeSwgdGhlIGFib3ZlIHNob3VsZCB3b3JrIHdpdGggYSBzaW5nbGUgZnVuY3Rpb24gY2FsbDoKcG9tYmVfZ29pZHNfc2ltcGxlIDwtIGxvYWRfYmlvbWFydF9nbyhzcGVjaWVzPSJzcG9tYmUiLCBvdmVyd3JpdGU9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkbF9yb3dzPWMoInBvbWJhc2VfdHJhbnNjcmlwdCIsICJnb19pZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvc3Q9ImZ1bmdpLmVuc2VtYmwub3JnIikKaGVhZChwb21iZV9nb2lkc19zaW1wbGVbWyJnbyJdXSkKaGVhZChwb21iZV9nb2lkcykKCiMjIFRoaXMgdXNlZCB0byB3b3JrLCBidXQgZG9lcyBzbyBubyBsb25nZXIgYW5kIEkgZG8gbm90IGtub3cgd2h5LgojIyBwb21iZSA8LSBzbShHZW5vbWljRmVhdHVyZXM6Om1ha2VUeERiRnJvbUJpb21hcnQoYmlvbWFydD0iZnVuZ2FsX21hcnQiLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YXNldD0ic3BvbWJlX2VnX2dlbmUiLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG9zdD0iZnVuZ2kuZW5zZW1ibC5vcmciKSkKCiMjIEkgYmV0IEkgY2FuIGdldCBhbGwgdGhpcyBpbmZvcm1hdGlvbiBmcm9tIGVuc2VtYmwgbm93LgojIyBUaGlzIHdhcyBmb3VuZCBhdCB0aGUgYm90dG9tIG9mOiBodHRwczovL3d3dy5iaW9zdGFycy5vcmcvcC8yMzIwMDUvCmxpbmsgPC0gImZ0cDovL2Z0cC5lbnNlbWJsZ2Vub21lcy5vcmcvcHViL3JlbGVhc2UtMzQvZnVuZ2kvZ2ZmMy9zY2hpem9zYWNjaGFyb215Y2VzX3BvbWJlL1NjaGl6b3NhY2NoYXJvbXljZXNfcG9tYmUuQVNNMjk0djIuMzQuZ2ZmMy5neiIKcG9tYmUgPC0gR2Vub21pY0ZlYXR1cmVzOjptYWtlVHhEYkZyb21HRkYobGluaywgZm9ybWF0PSJnZmYzIiwgb3JnYW5pc209IlNjaGl6b3NhY2NoYXJvbXljZXMgcG9tYmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXhvbm9teUlkPTQ4OTYpCgpwb21iZV90cmFuc2NyaXB0cyA8LSBhcy5kYXRhLmZyYW1lKEdlbm9taWNGZWF0dXJlczo6dHJhbnNjcmlwdHNCeShwb21iZSkpCmxlbmd0aHMgPC0gcG9tYmVfdHJhbnNjcmlwdHNbLCBjKCJncm91cF9uYW1lIiwid2lkdGgiKV0KY29sbmFtZXMobGVuZ3RocykgPC0gYygiSUQiLCJ3aWR0aCIpCiMjIFNvbWV0aGluZyB1c2VmdWwgSSBkaWRuJ3Qgbm90aWNlIGJlZm9yZToKIyMgbWFrZVRyYW5zY3JpcHREYkZyb21HRkYoKSAgIyMgRnJvbSBHZW5vbWljRmVhdHVyZXMsIG11Y2ggbGlrZSBteSBvd24gZ2ZmMmRmKCkKZ2ZmX2Zyb21fdHhkYiA8LSBHZW5vbWljRmVhdHVyZXM6OmFzR0ZGKHBvbWJlKQojIyB3aHkgaXMgR2VuZUlEOiBnZXR0aW5nIHByZWZpeGVkIHRvIHRoZSBJRHMhPwpnZmZfZnJvbV90eGRiJElEIDwtIGdzdWIoeD1nZmZfZnJvbV90eGRiJElELCBwYXR0ZXJuPSJHZW5lSUQ6IiwgcmVwbGFjZW1lbnQ9IiIpCndyaXR0ZW5fZ2ZmIDwtIHJ0cmFja2xheWVyOjpleHBvcnQuZ2ZmMyhnZmZfZnJvbV90eGRiLCBjb249InBvbWJlLmdmZiIpCmBgYAoKIyMgR09TZXEgdGVzdAoKYGBge3IgdGVzdF9nb3NlcX0Kc3VtbWFyeSh1cGRvd25fZ2VuZXMpCnRlc3RfZ2VuZXMgPC0gdXBkb3duX2dlbmVzJGRvd25fZ2VuZXMKcm93bmFtZXModGVzdF9nZW5lcykgPC0gcGFzdGUwKHJvd25hbWVzKHRlc3RfZ2VuZXMpLCAiLjEiKQpsZW5ndGhzJElEIDwtIHBhc3RlMChsZW5ndGhzJElELCAiLjEiKQpnb3NlcV9yZXN1bHQgPC0gc20oc2ltcGxlX2dvc2VxKHNpZ19nZW5lcz10ZXN0X2dlbmVzLCBnb19kYj1wb21iZV9nb2lkcywgbGVuZ3RoX2RiPWxlbmd0aHMpKQpoZWFkKGdvc2VxX3Jlc3VsdCRhbGxkYXRhKQpnb3NlcV9yZXN1bHQkcHZhbHVlX3Bsb3RzJG1mcF9wbG90Cgp0ZXN0X2dlbmVzIDwtIHVwZG93bl9nZW5lcyR1cF9nZW5lcwpyb3duYW1lcyh0ZXN0X2dlbmVzKSA8LSBwYXN0ZTAocm93bmFtZXModGVzdF9nZW5lcyksICIuMSIpCmdvc2VxX3Jlc3VsdCA8LSBzbShzaW1wbGVfZ29zZXEoc2lnX2dlbmVzPXRlc3RfZ2VuZXMsIGdvX2RiPXBvbWJlX2dvaWRzLCBsZW5ndGhfZGI9bGVuZ3RocykpCmhlYWQoZ29zZXFfcmVzdWx0JGFsbF9kYXRhKQpnb3NlcV9yZXN1bHQkcHZhbHVlX3Bsb3RzJGJwcF9wbG90CmBgYAoKIyMgQ2x1c3RlclByb2ZpbGVyIHRlc3QKCmNsdXN0ZXJQcm9maWxlciByZWFsbHkgcHJlZmVycyBhbiBvcmdkYiBpbnN0YW5jZSB0byB1c2UsIHdoaWNoIGlzIHByb2JhYmx5IHNtYXJ0LCBhcyB0aGV5IGFyZQpwcmV0dHkgbmljZS4gIFNhZGx5LCB0aGVyZSBpcyBubyBwcmUtZGVmaW5lZCBvcmdkYiBmb3IgcG9tYmUuLi4KCmBgYHtyIHRlc3RfY3AsIGV2YWw9RkFMU0V9CiMjIGhvbHkgY3JhcCBtYWtlT3JnUGFja2FnZUZyb21OQ0JJIGlzIHNsb3csIG5vIHNsb3dlciB0aGFuIHNvbWUgb2YgbWluZSwgc28gd2hvIGFtIEkgdG8gY29tcGxhaW4uCm9yZ2RiIDwtIEFubm90YXRpb25Gb3JnZTo6bWFrZU9yZ1BhY2thZ2VGcm9tTkNCSSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb249IjAuMSIsIGF1dGhvcj0iYXRiIDxhYmVsZXdAZ21haWwuY29tPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWludGFpbmVyPSJhdGIgPGFiZWxld0BnbWFpbC5jb20+IiwgdGF4X2lkPSI0ODk2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbnVzPSJTY2hpem9zYWNjaGFyb215Y2VzIiwgc3BlY2llcz0icG9tYmUiKQojIyBUaGlzIGNyZWF0ZWQgdGhlIGRpcmVjdG9yeSAnb3JnLnNwb21iZS5lZy5kYicKZGV2dG9vbHM6Omluc3RhbGxfbG9jYWwoIm9yZy5TcG9tYmUuZWcuZGIiKQpsaWJyYXJ5KG9yZy5TcG9tYmUuZWcuZGIpCiMjIERvbid0IGZvcmdldCB0byByZW1vdmUgdGhlIHRlcm1pbmFsIC4xIGZyb20gdGhlIGdlbmUgbmFtZXMuLi4KIyMgSWYgeW91IGRvIGZvcmdldCB0aGlzLCBpdCB3aWxsIGZhaWwgZm9yIG5vIGVhc2lseSB2aXNpYmxlIHJlYXNvbiB1bnRpbCB5b3UgcmVtZW1iZXIKIyMgdGhpcyBhbmQgZ2V0IHJlYWxseSBtYWQgYXQgeW91cnNlbGYuCnJvd25hbWVzKHRlc3RfZ2VuZXMpIDwtIGdzdWIocGF0dGVybj0iLjEkIiwgcmVwbGFjZW1lbnQ9IiIsIHg9cm93bmFtZXModGVzdF9nZW5lcykpCnBvbWJlX2dvaWRzW1siSUQiXV0gPC0gZ3N1YihwYXR0ZXJuPSIuMSQiLCByZXBsYWNlbWVudD0iIiwgeD1wb21iZV9nb2lkc1tbIklEIl1dKQpjcF9yZXN1bHQgPC0gc2ltcGxlX2NsdXN0ZXJwcm9maWxlcihzaWdfZ2VuZXM9dGVzdF9nZW5lcywgZG9fZGF2aWQ9RkFMU0UsIGRvX2dzZWE9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlX3RhYmxlPWFsbF9jb21iaW5lZCRkYXRhW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2RiPW9yZy5TcG9tYmUuZWcuZGIsIG9yZ2RiX3RvPSJBTElBUyIpCmNwX3Jlc3VsdFtbInB2YWx1ZV9wbG90cyJdXVtbImVnb19hbGxfbWYiXV0KIyMgWWF5IGJhciBwbG90cyEKYGBgCgpgYGB7ciB0ZXN0X3RwfQojIyBHZXQgcmlkIG9mIHRob3NlIHN0dXBpZCB0ZXJtaW5hbCAuMXMuCnJvd25hbWVzKHRlc3RfZ2VuZXMpIDwtIGdzdWIocGF0dGVybj0iLjEkIiwgcmVwbGFjZW1lbnQ9IiIsIHg9cm93bmFtZXModGVzdF9nZW5lcykpCnBvbWJlX2dvaWRzW1siSUQiXV0gPC0gZ3N1YihwYXR0ZXJuPSIuMSQiLCByZXBsYWNlbWVudD0iIiwgeD1wb21iZV9nb2lkc1tbIklEIl1dKQp0cF9yZXN1bHQgPC0gc20oc2ltcGxlX3RvcGdvKHNpZ19nZW5lcz10ZXN0X2dlbmVzLCBnb19kYj1wb21iZV9nb2lkcywgcHZhbF9jb2x1bW49ImxpbW1hX2FkanAiKSkKCnRwX3Jlc3VsdFtbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KdHBfcmVzdWx0W1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQpgYGAKCmBgYHtyIGdzdF90ZXN0fQojIyBHZXQgcmlkIG9mIHRob3NlIHN0dXBpZCB0ZXJtaW5hbCAuMXMuCiMjcm93bmFtZXModGVzdF9nZW5lcykgPC0gZ3N1YihwYXR0ZXJuPSIuMSQiLCByZXBsYWNlbWVudD0iIiwgeD1yb3duYW1lcyh0ZXN0X2dlbmVzKSkKcG9tYmVfZ29pZHNbWyJJRCJdXSA8LSBnc3ViKHBhdHRlcm49Ii4xJCIsIHJlcGxhY2VtZW50PSIiLCB4PXBvbWJlX2dvaWRzW1siSUQiXV0pCiMjIHVuaXZlcnNlX21lcmdlIGlzIHRoZSBjb2x1bW4gaW4gdGhlIGZpbmFsIGRhdGEgZnJhbWUgd2hlbi4KIyMgZ2ZmX3R5cGUgaXMgdGhlIGZpZWxkIGluIHRoZSBnZmYgZmlsZSBwcm92aWRpbmcgdGhlIGlkLCB0aGlzIG1heSBiZSByZWR1bmRhbnQgd2l0aAojIyB1bml2ZXJzZSBtZXJnZSwgdGhhdCBpcyBzb21ldGhpbmcgdG8gY2hlY2sgb24uLi4KZ3N0X3Jlc3VsdCA8LSBzbShzaW1wbGVfZ29zdGF0cyhzaWdfZ2VuZXM9dGVzdF9nZW5lcywgZ29fZGI9cG9tYmVfZ29pZHMsIHVuaXZlcnNlX21lcmdlPSJpZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2ZmX3R5cGU9ImdlbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdmZj0icG9tYmUuZ2ZmIiwgcHZhbF9jb2x1bW49ImxpbW1hX2FkanAiKSkKZ3N0X3Jlc3VsdFtbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KZ3N0X3Jlc3VsdFtbInB2YWx1ZV9wbG90cyJdXVtbImJwcF9wbG90X292ZXIiXV0KYGBgCgpgYGB7ciBzeXNpbmZvLCByZXN1bHRzPSJhc2lzIn0KcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKYGBgCg==